package com.klxedu.ms.gateway.zullfilter;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.web.bind.annotation.RequestMethod;

import com.google.gson.Gson;
import com.klxedu.ms.gateway.core.json.JsonErrorObject;
import com.klxedu.ms.gateway.core.json.ResponesCode;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

/**
 * 重复提交校验Filter
 * 
 * @author songhuiqing
 *
 */
public class RepeatSubmitFilter extends ZuulFilter {

	private static final String TOKEN_KEY_PREFIX = "RepeatSubmitToken#";
	private static final String TOKEN_KEY_SUFFIX_TIMESTAMP = "_timestamp";
	private static final String TOKEN_KEY_SUFFIX_DATA = "_data";
	private static int EXPIRED_TIMESTAMP = 5000;// 有效期

	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		String requestURI = request.getRequestURI();
		String method = request.getMethod();
		Map<String, String[]> parameterMap = request.getParameterMap();
		if (parameterMap == null || parameterMap.isEmpty()) {
			return null;
		}
		StringBuilder requestParams = new StringBuilder();
		Set<String> keySet = parameterMap.keySet();
		Iterator<String> iterator = keySet.iterator();
		List<String> params = new ArrayList<>();
		while (iterator.hasNext()) {
			params.add(iterator.next());
		}
		Collections.sort(params);
		for (String param : params) {
			String[] values = parameterMap.get(param);
			Arrays.sort(values);
			requestParams.append(param).append("=").append(Arrays.asList(values)).append(";");
		}
		String sessionKey = TOKEN_KEY_PREFIX + requestURI + "#" + method + TOKEN_KEY_SUFFIX_DATA;
		String timeKey = TOKEN_KEY_PREFIX + requestURI + "#" + method + TOKEN_KEY_SUFFIX_TIMESTAMP;
		String md5Hex = DigestUtils.md5Hex(requestParams.toString());
		String value = (String) request.getSession().getAttribute(sessionKey);
		Long timestamp = (Long) request.getSession().getAttribute(timeKey);
		long current = System.currentTimeMillis();
		request.getSession().setAttribute(sessionKey, md5Hex);// 设置当前用户对应请求到session中
		request.getSession().setAttribute(timeKey, current);// 设置当前用户对应请求时间戳

		if (value != null && value.equalsIgnoreCase(md5Hex) && timestamp != null
				&& (current - timestamp) < EXPIRED_TIMESTAMP) {
            //过滤该请求，不往下级服务去转发请求，到此结束
			ctx.setSendZuulResponse(false);
			ctx.setResponseStatusCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			JsonErrorObject<Object> jsonErrorObject = new JsonErrorObject<>("请求：" + requestURI + ",请求方式：" + method + "重复提交");
			jsonErrorObject.setCode(ResponesCode.ERROR_REPEAT_SUBMIT);
			ctx.setResponseBody(new Gson().toJson(jsonErrorObject));
		}

		return null;
	}

	@Override
	public boolean shouldFilter() {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		String method = request.getMethod();
		return RequestMethod.POST.toString().equalsIgnoreCase(method);
	}

	@Override
	public int filterOrder() {
		return FORM_BODY_WRAPPER_FILTER_ORDER + 1;
	}

	@Override
	public String filterType() {
		return PRE_TYPE;
	}

}
